package com.fawkes.project.example.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fawkes.core.base.api.ApiResponseBody;
import com.fawkes.core.enums.BizCodeMsgEnum;
import com.fawkes.core.enums.DeleteFlagEnum;
import com.fawkes.core.exception.BusinessException;
import com.fawkes.core.utils.SpringTool;
import com.fawkes.core.utils.StringPool;
import com.fawkes.core.utils.jackson.JsonTool;
import com.fawkes.project.example.client.IBpmClient;
import com.fawkes.project.example.common.constants.FormConstants;
import com.fawkes.project.example.common.enums.MapperMethodEnums;
import com.fawkes.project.example.common.param.*;
import com.fawkes.project.example.common.utils.MyEntityTool;
import com.fawkes.project.example.common.vo.FormVO;
import com.fawkes.project.example.service.ICommonService;
import com.fawkes.stream.msg.send.bpm.BpmFormProcessStateMsg;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 表单通用服务实现类
 *
 * @author li_y29
 * @date 2019-12-02
 */
@Service
@Slf4j
public class CommonServiceImpl implements ICommonService {
    @Autowired
    private IBpmClient iBpmClient;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResponseBody saveForm(FormCommitParam formCommitParam) throws Exception {
        if (StringUtils.isEmpty(formCommitParam.getEntityName()) || formCommitParam.getEntityObject() == null) {
            return ApiResponseBody.error(BizCodeMsgEnum.PARAM_ERROR);
        }
        FormVO formVO = new FormVO();
        // 主表Mapper
        Object clazz = SpringTool.getBean(StringUtils.uncapitalize(formCommitParam.getEntityName()) + FormConstants.FORM_MAPPER);
        if (clazz == null) {
            throw new BusinessException(BizCodeMsgEnum.EM_FORM_BEAN_ERROR);
        }
        JSONObject entityObject = formCommitParam.getEntityObject();
        String methodString = MapperMethodEnums.insertSelective.getMethod();
        if (entityObject.get(FormConstants.FORM_ID) != null) {
            methodString = MapperMethodEnums.updateByPrimaryKeySelective.getMethod();
        }
        Method[] methods = clazz.getClass().getMethods();
        // 执行新增更新
        for (Method method : methods) {
            if (method.getName().equals(methodString)) {
                Class parameterType = method.getParameterTypes()[0];
                Object param = JsonTool.parse(formCommitParam.getEntityObject().toString(), parameterType);
                if (entityObject.get(FormConstants.FORM_ID) == null) {
                    MyEntityTool.insertEntity(param);
                } else {
                    MyEntityTool.updateEntity(param);
                }
                method.invoke(clazz, param);
                formVO.setEntityObject(param);
                break;
            }
        }

        // 明细表Mapper
        List<FormDetailParam> detailParamList = formCommitParam.getDetailParamList();
        if (!CollectionUtils.isEmpty(detailParamList)) {
            // 返回明细表数据
            List<FormDetailParam> rtnDetailList = new ArrayList();
            // 遍历明细表
            for (FormDetailParam detailParam : detailParamList) {
                JSONArray entityDetailArray = detailParam.getDetailEntityArray();
                if (entityDetailArray == null || entityDetailArray.size() == 0) {
                    continue;
                }
                Object detailClazz = SpringTool.getBean(StringUtils.uncapitalize(detailParam.getDetailEntityName() + FormConstants.FORM_MAPPER));
                if (detailClazz == null) {
                    throw new BusinessException(BizCodeMsgEnum.EM_FORM_BEAN_DETAIL_ERROR);
                }
                Method[] detailMethods = detailClazz.getClass().getMethods();
                // 明细表对象
                JSONArray detailList = new JSONArray();
                for (int i = 0; i < entityDetailArray.size(); i++) {
                    JSONObject entityDetail = entityDetailArray.getJSONObject(i);
                    Object formIdObject = entityDetail.get(FormConstants.FORM_ID);
                    Object deleteFlageObject = entityDetail.get(FormConstants.FORM_DELETE_FLAG);
                    if (formIdObject == null && deleteFlageObject != null && DeleteFlagEnum.DATA_WARN.getFlag().equals(deleteFlageObject.toString())) {
                        continue;
                    }
                    // 反射方法
                    String detailMethodString;
                    if (formIdObject == null) {
                        detailMethodString = MapperMethodEnums.insertSelective.getMethod();
                    } else if (deleteFlageObject != null && DeleteFlagEnum.DATA_WARN.getFlag().equals(deleteFlageObject.toString())) {
                        detailMethodString = MapperMethodEnums.deleteByPrimaryKey.getMethod();
                    } else {
                        detailMethodString = MapperMethodEnums.updateByPrimaryKeySelective.getMethod();
                    }
                    // 执行方法
                    for (Method method : detailMethods) {
                        if (method.getName().equals(detailMethodString)) {
                            if (MapperMethodEnums.deleteByPrimaryKey.getMethod().equals(detailMethodString)) {
                                method.invoke(detailClazz, Long.valueOf(entityDetail.get(FormConstants.FORM_ID).toString()));
                            } else {
                                Class parameterType = method.getParameterTypes()[0];
                                JSONObject jsonObject = JSONObject.parseObject(JsonTool.toJson(formVO.getEntityObject()));
                                entityDetail.put(FormConstants.FORM_FK_ID, jsonObject.get(FormConstants.FORM_ID));
                                Object param = JsonTool.parse(entityDetail.toString(), parameterType);
                                if (formIdObject == null) {
                                    MyEntityTool.insertEntity(param);
                                } else {
                                    MyEntityTool.updateEntity(param);
                                }
                                method.invoke(detailClazz, param);
                                detailList.add(JSONObject.parseObject(JsonTool.toJson(param)));
                            }
                            break;
                        }
                    }
                }
                FormDetailParam rtnDetailParam = new FormDetailParam();
                rtnDetailParam.setDetailEntityName(detailParam.getDetailEntityName());
                rtnDetailParam.setDetailEntityArray(detailList);
                rtnDetailList.add(rtnDetailParam);
            }
            formVO.setDetailParamList(rtnDetailList);
        }
        //流程操作
        if (formCommitParam.getFormProcessParam() != null) {
            JSONObject formObject = JSONObject.parseObject(JsonTool.toJson(formVO.getEntityObject()));
            formCommitParam.getFormProcessParam().setBizId(formObject.get(FormConstants.FORM_ID).toString());
            // 发起流程
            if (StringUtils.isEmpty(formCommitParam.getFormProcessParam().getTaskId())) {
                startProcess(formCommitParam.getFormProcessParam());
            }
            // 审批流程
            else {
                completeProcess(formCommitParam.getFormProcessParam());
            }
        }
        return ApiResponseBody.defaultSuccess(formVO);
    }

    @Override
    public ApiResponseBody queryForm(FormQueryParam formQueryParam) throws Exception {
        FormVO formVO = new FormVO();
        String methodString = MapperMethodEnums.selectByPrimaryKey.getMethod();
        Object clazz = SpringTool.getBean(StringUtils.uncapitalize(formQueryParam.getEntityName()) + FormConstants.FORM_MAPPER);
        if (clazz == null) {
            throw new BusinessException(BizCodeMsgEnum.EM_FORM_BEAN_ERROR);
        }
        Method[] methods = clazz.getClass().getMethods();
        for (Method method : methods) {
            if (method.getName().equals(methodString)) {
                formVO.setEntityObject(method.invoke(clazz, formQueryParam.getId()));
                break;
            }
        }
        List<String> detailEntityNameList = formQueryParam.getDetailEntityNameList();
        if (CollectionUtils.isEmpty(detailEntityNameList)) {
            return ApiResponseBody.defaultSuccess(formVO);
        }
        // 返回明细表数据
        List<FormDetailParam> rtnDetailList = new ArrayList<>();
        // 遍历明细表
        for (String detailEntityName : detailEntityNameList) {
            // 明细表Mapper
            Object detailClazz = SpringTool.getBean(StringUtils.uncapitalize(StringUtils.capitalize(detailEntityName)) + FormConstants.FORM_MAPPER);
            if (detailClazz == null) {
                throw new BusinessException(BizCodeMsgEnum.EM_FORM_BEAN_DETAIL_ERROR);
            }
            // 返回明细表单条数据
            FormDetailParam rtnDetailParam = new FormDetailParam();
            rtnDetailParam.setDetailEntityName(detailEntityName);
            Class<?> exampleClass = Class.forName(FormConstants.MODEL_PACKAGE_PATH + StringPool.DOT + detailEntityName + FormConstants.FORM_EXAMPLE);
            Object example = exampleClass.newInstance();
            Method method = example.getClass().getMethod(MapperMethodEnums.createCriteria.getMethod(), null);
            Object criteria = method.invoke(example);
            Method fkIdEqualTo = criteria.getClass().getMethod(MapperMethodEnums.andFkIdEqualTo.getMethod(), String.class);
            fkIdEqualTo.invoke(criteria, formQueryParam.getId().toString());
            Method[] detailMethods = detailClazz.getClass().getMethods();
            for (Method detailMethod : detailMethods) {
                if (detailMethod.getName().equals(MapperMethodEnums.selectByExample.getMethod())) {
                    rtnDetailParam.setDetailEntityArray(JSONObject.parseArray(JsonTool.toJson(detailMethod.invoke(detailClazz, example))));
                    break;
                }
            }
            rtnDetailList.add(rtnDetailParam);
        }
        formVO.setDetailParamList(rtnDetailList);
        return ApiResponseBody.defaultSuccess(formVO);
    }

    @Override
    public void updateFormProcessState(BpmFormProcessStateMsg processState, Object clazz) {
        JSONObject entityObject = new JSONObject();
        entityObject.put(FormConstants.FORM_ID, Long.valueOf(processState.getBizId()));
        entityObject.put(FormConstants.FORM_PROCESS_STATE, processState.getProcessState());
        Method[] methods = clazz.getClass().getMethods();
        try {
            // 执行新增更新
            for (Method updateMethod : methods) {
                if (updateMethod.getName().equals(MapperMethodEnums.updateByPrimaryKeySelective.getMethod())) {
                    Class parameterType = updateMethod.getParameterTypes()[0];
                    Object param = JsonTool.parse(entityObject.toString(), parameterType);
                    updateMethod.invoke(clazz, param);
                    break;
                }
            }
        } catch (Exception e) {
            log.error("修改流程状态出错", e);
        }
    }

    /**
     * 发起流程
     *
     * @author li_y29
     * @date 2021-4-14
     */
    private void startProcess(FormProcessParam formProcessParam) {
        ApiResponseBody apiResponseBody = iBpmClient.startProcess(formProcessParam.getModelKey(), formProcessParam.getFormKey(), formProcessParam.getBizId(), formProcessParam.getVariable(), formProcessParam.getComment(), formProcessParam.getStageFlag(), null, null);
        if (BizCodeMsgEnum.SYS_ERROR.getCode().equals(apiResponseBody.getCode())) {
            throw new BusinessException("发起流程失败，表单数据回滚");
        }
    }

    /**
     * 审批流程
     *
     * @author sun_ht
     * @date 2021-5-24
     */
    private void completeProcess(FormProcessParam formProcessParam) {
        ApiResponseBody apiResponseBody = iBpmClient.completeProcess(formProcessParam.getTaskId(), formProcessParam.getComment(), null, formProcessParam.getVariable(), formProcessParam.getStageFlag());
        if (BizCodeMsgEnum.SYS_ERROR.getCode().equals(apiResponseBody.getCode())) {
            throw new BusinessException("审批流程失败，表单数据回滚");
        }
    }
}
